# 3. 利用本周学习的知识实现如下效果的程序：
#
# 1. server端监听指定的tcp端口
# 2. server端预先实现简单加减法的代码(可以自行扩展其他更复杂功能)
# 3. client端可以通过socket连接与server端通信传输需要参数
# 4. server端根据传的参数计算结果并返回
# 5. client端打印返回结果
import selectors
import socket
import threading
import re


class MathServer:

    def __init__(self, ip='localhost', port=6699):
        self.addr = ip, port
        self.server = socket.socket()
        self.server.setblocking(False)
        self.selector = selectors.DefaultSelector()
        self.event = threading.Event()
        self.userinput = ''
        self.result = ''

    def start(self):
        self.server.bind(self.addr)
        self.server.listen()
        print("Server is listening...\n")
        key = self.selector.register(self.server, selectors.EVENT_READ, self.accept)
        threading.Thread(target=self.select, name='select').start()

    def select(self):
        with self.selector:
            while not self.event.is_set():
                events = self.selector.select(0.5)
                for key, mask in events:
                    key.data(key.fileobj, mask)

    def accept(self, server, mask):
        conn, addr = server.accept()
        print("{} is connected.".format(addr))
        conn.setblocking(False)
        key = self.selector.register(conn, selectors.EVENT_READ, self.recv)

    def recv(self, conn, mask):
        try:
            self.userinput = conn.recv(1024)
            if self.userinput == b'quit' or self.userinput == b'':
                print("client {} disconnect.".format(conn.getpeername()))
                conn.send(b'')
                self.selector.unregister(conn)
                conn.close()
                return
            print("client {} input: {}".format(conn.getpeername(), self.userinput.decode()))
            #以下解析计算式并返回结果
            self.result = self.compute()
            if self.result == None:
                conn.send('please input legal calculation formula like 2+3 or 2.01 * 5 or quit!\n'.encode())
            else:
                conn.send(str(self.result).encode())
        except Exception as e:
            print(e)

    def compute(self):  #解析用户输入并计算结果
        regex = re.compile('\s*(?P<d1>\d+(.\d+)?)\s*(?P<op>[\+\-\*\/])\s*(?P<d2>\d+(.\d+)?)\s*')
        result = regex.fullmatch(self.userinput.decode())
        if result == None:
            return None
        else:
            d1 = float(result.group('d1'))
            op = result.group('op')
            d2 = float(result.group('d2'))
            if op == '+':
                return d1 + d2
            elif op == '-':
                return d1 - d2
            elif op == '*':
                return d1 * d2
            elif op == '/':
                return d1 / d2
            else:
                return None


    def stop(self):
        self.event.set()

if __name__ == '__main__':
    while True:
        port = input("please input listen port: ")
        port = int(port)
        if port <1000 or port > 65535:
            print("please input port between 1000 and 65535\n")
        else:
            break
    ms = MathServer(port=port)
    ms.start()




